import torch
from torch import nn


class LSTM_Net(nn.Module):

    def __init__(self, input_size, hidden_size, num_layers, output_size, batch_size, seq_length) -> None:
        super(LSTM_Net, self).__init__()
        self.input_size = input_size
        self.hidden_size = hidden_size
        self.num_layers = num_layers
        self.output_size = output_size
        self.batch_size = batch_size
        self.seq_length = seq_length
        self.num_directions = 1  # 单向LSTM
        self.lstm = nn.LSTM(input_size=input_size, hidden_size=hidden_size, num_layers=num_layers,
                            batch_first=True)  # LSTM层
        self.fc = nn.Linear(hidden_size, output_size)
        self.name = 'trained_LSTM_Net'

    def forward(self, x):
        # batch_size, seq_len = x.size()[0], x.size()[1]  # x.shape=(604,3,3)
        h_0 = torch.randn(self.num_directions * self.num_layers, x.size(0), self.hidden_size, device=x.device)
        c_0 = torch.randn(self.num_directions * self.num_layers, x.size(0), self.hidden_size, device=x.device)
        # output(batch_size, seq_len, num_directions * hidden_size)
        output, _ = self.lstm(x, (h_0, c_0))  # output(5, 30, 64)

        output, (h_n, c_n) = self.lstm(x, (h_0, c_0))

        pred = self.fc(output)  # (5, 30, 1)
        pred = pred[:, -1, :]  # (5, 1)
        return pred

    def getNetName(self):
        return self.name


class GRU_Net(nn.Module):
    def __init__(self, input_size, hidden_size, num_layers, output_size, batch_size, seq_length):
        super().__init__()
        self.input_size = input_size
        self.hidden_size = hidden_size
        self.num_layers = num_layers
        self.output_size = output_size
        self.batch_size = batch_size
        self.seq_length = seq_length
        self.gru = torch.nn.GRU(self.input_size, self.hidden_size, self.num_layers, batch_first=True)
        self.linear = torch.nn.Linear(self.hidden_size, self.output_size)
        self.name = 'trained_GRU_Net'

    def forward(self, input_seq):
        output, _ = self.gru(input_seq, None)
        pred = self.linear(output)
        pred = pred[:, -1, :]
        return pred

    def getNetName(self):
        return self.name









